//
//  slab.h
//  Wi-Fi Party macOS
//
//  Created by 许煜恒 on 2022/10/21.
//

#ifndef slab_h
#define slab_h

#include <assert.h>
#include <pthread.h>
#include <cstdlib>
#include <cstdio>

template <typename object>
class Slab {
    unsigned int length;
    struct objTableItem{
        char content[sizeof(object)];
        objTableItem *prev, *next;
    } *table, *freeEntry;
    pthread_mutex_t lock;

public:
    Slab(unsigned int length){
        assert(length>3);

        this->length=length;
        this->table=new struct objTableItem[length+1];
        for(unsigned int i=1;i<length;i++){
            this->table[i].next=&this->table[i+1];
            this->table[i].prev=&this->table[i-1];
        }
        this->table[0].next=&this->table[1];
        this->table[0].prev=&this->table[length];
        this->table[length].next=&this->table[0];
        this->table[length].prev=&this->table[length-1];

        this->freeEntry=&this->table[0];
        this->lock=PTHREAD_MUTEX_INITIALIZER;

    }

    object* alloc(){
        pthread_mutex_lock(&this->lock);
        if(this->freeEntry->next==this->freeEntry){
            printf("Slab is not enough\n");
            exit(1);
        }
        objTableItem *targetPosition=this->freeEntry->next;
        targetPosition->next->prev=targetPosition->prev;
        targetPosition->prev->next=targetPosition->next;
        pthread_mutex_unlock(&this->lock);
        return (object*)&targetPosition->content;
    }

    void release(object* addr){
        pthread_mutex_lock(&this->lock);
        objTableItem *targetPosition=(objTableItem*) addr;
        targetPosition->next=this->freeEntry->next;
        targetPosition->prev=this->freeEntry;
        this->freeEntry->next->prev=targetPosition;
        this->freeEntry->next=targetPosition;
        pthread_mutex_unlock(&this->lock);

    }

    ~Slab(){
        delete [] this->table;
    }
};

#endif /* slab_h */
